package main;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Vector;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;

public class commandLine {

	/**
	 * 
	 * @param command
	 * @return
	 * @deprecated
	 */
	public boolean launchCommand(String command) {
		System.out.println(command);
		Process child;
		Thread readOut;
		try {
			/**/
			ProcessBuilder builder = new ProcessBuilder(command.split(" "));
			builder.redirectErrorStream(true);
			builder.directory(null);
			child = builder.start();
			/**/
			// child = Runtime.getRuntime().exec(command);
			// Get the input stream and read from it
			final InputStream in = child.getInputStream();
			readOut = new Thread(new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
					BufferedReader input = new BufferedReader(
							new InputStreamReader(in));
					String line = null;
					System.out.println();
					try {
						while ((line = input.readLine()) != null) {
							if (!line.equalsIgnoreCase(""))
								System.out.println(line);
						}
						input.close();
						in.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
			readOut.start();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}

		int finComando = -1;
		while (finComando == -1) {
			try {
				finComando = child.exitValue();
			} catch (Exception e) {
				// TODO: handle exception
				// e.printStackTrace();
			}
		}
		readOut.interrupt();
		System.out.println(finComando);
		if (finComando != 0) {
			return false;
		}

		return true;
	}

	/**
	 * 
	 * @param command
	 * @param noWait
	 * @return
	 * @deprecated
	 */
	public boolean launchCommand(String command, boolean noWait) {
		System.out.println(command);
		Process child = null;
		try {
			child = Runtime.getRuntime().exec(command);
			// Get the input stream and read from it
			final InputStream in = child.getInputStream();
			final BufferedReader input = new BufferedReader(
					new InputStreamReader(in));
			String line = null;
			System.out.println();
			if (!noWait) {
				while ((line = input.readLine()) != null) {
					if (!line.equalsIgnoreCase(""))
						System.out.println(line);
				}
			}
			input.close();
			in.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}

		// if (!noWait) {
		int finComando = -1;
		while (finComando == -1) {
			try {
				finComando = child.exitValue();
			} catch (Exception e) {
				// TODO: handle exception
				// e.printStackTrace();
			}
		}
		System.out.println(finComando);
		if (finComando != 0) {
			return false;
		}
		// }

		return true;
	}

	public boolean launchCommand(String command, Vector<String> out) {
		try {
			if (out == null) {
				Vector<String> outTemp = new Vector<String>();
				return launchCommand(command, outTemp, 1000);
			} else {
				return launchCommand(command, out, 1000);
			}
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			System.err.println("TimeOutEx");
			return false;
		}
	}

	/**
	 * Function for launch out commands
	 * 
	 * @param command
	 * @param out
	 * @param maxTimeout
	 * @return
	 * @throws TimeoutException
	 */
	public boolean launchCommand(String command, Vector<String> out,
			long maxTimeout) throws TimeoutException {
		int executionTimeout = 60000;
		Process child = null;
		// long timeOut;
		try {
			ProcessBuilder builder = new ProcessBuilder(command.split(" "));
			System.out.println(builder.command());
			builder.redirectErrorStream(true);
			builder.directory(null);
			child = builder.start();
			InputStream in = child.getInputStream();

			// Start input reader
			BufferedReader input = new BufferedReader(new InputStreamReader(in));
			commandReader cmdReader = new commandReader(out, input, maxTimeout);
			cmdReader.start();

			int finComando = -1;
			long timeOut = System.currentTimeMillis();
			while ((finComando == -1)
					&& !cmdReader.timeOutBoolean.get()
					&& ((timeOut + executionTimeout) >= System
							.currentTimeMillis())) {
				try {
					finComando = child.exitValue();
				} catch (Exception e) {
					// TODO: handle exception
				}
			}
			cmdReader.commandFinished.set(true);
			try {
				cmdReader.join(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			input.close();
			in.close();

			out = cmdReader.out;

			if (cmdReader.timeOutBoolean.get()) {
				throw new TimeoutException();
			}

			System.out.println(finComando);
			if ((finComando != 0) && (finComando != 141)) {
				return false;
			}
		} catch (IOException e) {
			e.printStackTrace();
			child.destroy();
			return false;
		} finally {
			child.destroy();
		}

		return true;
	}

	private static class commandReader extends Thread {
		long maxTimeout = 0;
		BufferedReader input;
		Vector<String> out;
		AtomicBoolean timeOutBoolean = new AtomicBoolean(false);
		AtomicBoolean commandFinished = new AtomicBoolean(false);
		AtomicBoolean readFinished = new AtomicBoolean(false);

		public commandReader(Vector<String> m_out, BufferedReader m_input,
				long m_maxTimeout) {
			out = m_out;
			input = m_input;
			maxTimeout = m_maxTimeout;
		}

		public void run() {
			String line = "";
			long timeOut = System.currentTimeMillis();
			while ((line != null)
					&& (timeOut + maxTimeout) > System.currentTimeMillis()) {
				try {
					if (input.ready()) {
						line = input.readLine();
						System.out.println(line);
						if (!line.equalsIgnoreCase("")) {
							out.add(line);
						}
						timeOut = System.currentTimeMillis();
					} else {
						if (commandFinished.get()) {
							break;
						}
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if ((timeOut + maxTimeout) < System.currentTimeMillis()) {
				timeOutBoolean.set(true);
			}
			readFinished.set(true);
		}
	}

	/**
	 * Function for launch out commands
	 * 
	 * @param command
	 * @param out
	 * @param maxTimeout
	 * @return
	 * @throws TimeoutException
	 */
	public boolean launchCommand_backup(String command, Vector<String> out,
			long maxTimeout) throws TimeoutException {
		System.out.println(command);
		Process child = null;
		// long timeOut;
		try {
			ProcessBuilder builder = new ProcessBuilder(command.split(" "));
			builder.redirectErrorStream(true);
			builder.directory(null);
			child = builder.start();
			InputStream in = child.getInputStream();
			BufferedReader input = new BufferedReader(new InputStreamReader(in));
			String line = "";
			long timeOut = System.currentTimeMillis();
			while ((line != null)
					&& (timeOut + maxTimeout) > System.currentTimeMillis()) {
				if (input.ready()) {
					line = input.readLine();
					if (!line.equalsIgnoreCase("")) {
						out.add(line);
					}
					timeOut = System.currentTimeMillis();
				}
			}
			input.close();
			in.close();
			// } catch (IOException e) {
			// TODO Auto-generated catch block
			// e.printStackTrace();
			// return false;
			// }

			// TODO timeout?
			if ((timeOut + maxTimeout) < System.currentTimeMillis()) {
				throw new TimeoutException();
			}
			int finComando = -1;
			while (finComando == -1) {
				try {
					finComando = child.exitValue();
				} catch (Exception e) {
					// TODO: handle exception
				}
			}
			System.out.println(finComando);
			if ((finComando != 0) && (finComando != 141)) {
				return false;
			}
		} catch (IOException e) {
			e.printStackTrace();
			child.destroy();
			return false;
		} finally {
			child.destroy();
		}

		return true;
	}

	/**
	 * 
	 * @param command
	 * @param out
	 * @param path
	 * @return
	 * @deprecated
	 */
	public boolean launchCommandApk(String command, Vector<AppApk> out,
			String path) {
		System.out.println(command);
		Process child;
		try {
			child = Runtime.getRuntime().exec(command);
			// Get the input stream and read from it
			InputStream in = child.getInputStream();
			BufferedReader input = new BufferedReader(new InputStreamReader(in));
			String line = null;
			while ((line = input.readLine()) != null) {
				if (!line.equalsIgnoreCase("")) {
					AppApk apk = new AppApk(path, line);
					out.add(apk);
				}
			}
			input.close();
			in.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}

		int finComando = -1;
		while (finComando == -1) {
			try {
				finComando = child.exitValue();
			} catch (Exception e) {
				// TODO: handle exception
				// e.printStackTrace();
			}
		}
		System.out.println(finComando);
		if (finComando != 0) {
			return false;
		}

		return true;
	}

	public int executeCommandLine(final String commandLine,
			final boolean printOutput, final boolean printError,
			final long timeout) throws IOException, InterruptedException,
			TimeoutException {
		System.out.println(commandLine);
		Runtime runtime = Runtime.getRuntime();
		Process process = runtime.exec(commandLine);
		/* Set up process I/O. */
		if (printOutput) {
			final InputStream in = process.getInputStream();
			final BufferedReader input = new BufferedReader(
					new InputStreamReader(in));
			Thread readOut = new Thread(new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
					String line = null;
					System.out.println();
					try {
						while ((line = input.readLine()) != null) {
							if (!line.equalsIgnoreCase("")) {
								System.out.println(line);
							}
						}
						input.close();
						in.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
			readOut.start();
		}
		// ...
		Worker worker = new Worker(process);
		worker.start();
		try {
			worker.join(timeout);
			if (worker.exit != null)
				return worker.exit;
			else
				throw new TimeoutException();
		} catch (InterruptedException ex) {
			worker.interrupt();
			Thread.currentThread().interrupt();
			throw ex;
		} finally {
			process.destroy();
		}
	}

	private static class Worker extends Thread {
		private final Process process;
		private Integer exit;

		private Worker(Process process) {
			this.process = process;
		}

		public void run() {
			try {
				exit = process.waitFor();
			} catch (InterruptedException ignore) {
				return;
			}
		}
	}
}
